package org.bee.controller;

import org.bee.EnumUtils;
import org.bee.PageUtil;
import org.bee.ResultTool;
import org.bee.enums.IsDelete;
import org.bee.enums.JobConcurrent;
import org.bee.enums.JobStatus;
import org.bee.enums.ResultCode;
import org.bee.exception.ExceptionUtils;
import org.bee.id.UUIDUtils;
import org.bee.input.BatchJobInsertVo;
import org.bee.input.BatchJobSearchVo;
import org.bee.input.BatchJobUpdateVo;
import org.bee.input.CronParserVo;
import org.bee.model.BatchJob;
import org.bee.model.result.Result;
import org.bee.output.BatchJobOut;
import org.bee.secuirty.annotation.ApiAuth;
import org.bee.secuirty.context.CurrentUser;
import org.bee.service.BatchJobService;
import org.bee.service.SysJobService;
import org.bee.string.StringUtils;
import org.bee.transaction.TransUtils;
import org.bee.transaction.Transaction;
import org.quartz.CronExpression;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 定时任务调度表控制器
 */
@RestController
@RequestMapping("/batchJob")
public class BatchJobController {
    Logger logger = LoggerFactory.getLogger(BatchJobController.class);


    private final BatchJobService batchJobService;

    private final SysJobService sysJobService;

    public BatchJobController(BatchJobService batchJobService, SysJobService sysJobService) {
        this.batchJobService = batchJobService;
        this.sysJobService = sysJobService;
    }

    /**
     * 新增定时任务调度表
     * @param batchJobInsertVo 新增参数
     * @return 新增结果
     */
    @PostMapping("insert")
    @ApiAuth(value="batchJob.insert",description= "新增定时任务调度表")
    public Result insert(@RequestBody BatchJobInsertVo batchJobInsertVo) {
        Result result = ResultTool.success();
        Transaction trans = null;
        try {
            BatchJob batchJob = new BatchJob();
            BeanUtils.copyProperties(batchJobInsertVo, batchJob);
            batchJob.setId(UUIDUtils.simpleUuid());
            batchJob.setCreateUser(CurrentUser.getUser().getUserId());
            batchJob.setCreateTime(new Date());
            batchJob.setIsDeleted(Boolean.valueOf(IsDelete.FALSE.getCode()));
            trans= TransUtils.getTrans();
            trans.begin();
            batchJobService.insert(batchJob);
            trans.commit();
        } catch (Exception e) {
            TransUtils.rollback(trans);
            result = ResultTool.fail();
            logger.error(e.getMessage(), ExceptionUtils.getFullStackTrace(e));
            return result;
        }
        return result;
    }

    /**
     * 删除定时任务调度表
     * @param id id
     * @return 删除结果
     */
    @DeleteMapping("delete")
    @ApiAuth(value="batchJob.delete",description="删除定时任务调度表")
    public Result delete(@RequestParam("id") String id) {
        Result result = ResultTool.success();
        Transaction trans = null;
        if (id == null|| id.isEmpty()) {
            result = ResultTool.fail(ResultCode.PARAM_NOT_COMPLETE);
            return result;
        }
        try {
            trans= TransUtils.getTrans();
            trans.begin();
            batchJobService.delete(id,false);
            trans.commit();
        } catch (Exception e) {
            TransUtils.rollback(trans);
            result = ResultTool.fail();
            logger.error(e.getMessage(), ExceptionUtils.getFullStackTrace(e));
            return result;
        }
        return result;
    }

    /**
     * 修改定时任务调度表
     * @param batchJobUpdateVo 修改参数
     * @return 修改结果
     */
    @PostMapping("update")
    @ApiAuth(value="batchJob.update",description="修改定时任务调度表")
    public Result update(@RequestBody BatchJobUpdateVo batchJobUpdateVo) {
        Result result = ResultTool.success();
        Transaction trans = null;
        try {
            BatchJob batchJob = new BatchJob();
            BeanUtils.copyProperties(batchJobUpdateVo, batchJob);
            batchJob.setUpdateUser(CurrentUser.getUser().getUserId());
            batchJob.setUpdateTime(new Date());
            trans= TransUtils.getTrans();
            trans.begin();
            batchJobService.update(batchJob);
            sysJobService.update(batchJob);
            trans.commit();
        } catch (Exception e) {
            TransUtils.rollback(trans);
            result = ResultTool.fail();
            result.setMsg(e.getMessage());
            logger.error(e.getMessage(), ExceptionUtils.getFullStackTrace(e));
            return result;
        }
        return result;
    }

    /**
     * 根据id查询定时任务调度表
     * @param id id
     * @return 定时任务调度表结果
     */
    @GetMapping("selectById")
    @ApiAuth(value="batchJob.selectById",description="根据id查询定时任务调度表")
    public Result selectById(String id) {
        Result result = ResultTool.success();
        if(StringUtils.isEmpty(id)){
            result = ResultTool.fail(ResultCode.PARAM_NOT_COMPLETE);
            result.setMsg("id不能为空");
        }
        BatchJob batchJob = batchJobService.selectById(id);
        result.setData(batchJob);
        return result;
    }

    /**
     * 分页查询查询定时任务调度表
     * @param batchJobSearchVo 查询参数
     * @return 查询结果
     */
    @PostMapping("pageQuery")
    @ApiAuth(value="batchJob.pageQuery",description="分页查询定时任务调度表")
    public Result select(@RequestBody BatchJobSearchVo batchJobSearchVo) {
        Result result = ResultTool.success();
        PageUtil.setPage(batchJobSearchVo.getCurrent(),batchJobSearchVo.getSize());
        List<BatchJob> select = batchJobService.select(batchJobSearchVo);
        List<BatchJobOut> selectOut = new ArrayList<>();
        select.forEach(batchJob -> {
            BatchJobOut batchJobOut = new BatchJobOut();
            BeanUtils.copyProperties(batchJob, batchJobOut);
            batchJobOut.setStatusMean(EnumUtils.code2Desc(JobStatus.class,batchJob.getStatus()));
            batchJobOut.setConcurrentMean(EnumUtils.code2Desc(JobConcurrent.class,batchJob.getConcurrent()));
            selectOut.add(batchJobOut);
        });
        result.setPageData(selectOut);
        return result;
    }

    /**
     * 立即执行一次
     * @param batchJob 批处理信息
     * @return 执行结果
     */
    @PostMapping("/run")
    @ApiAuth(value="batchJob.run",description="定时任务立即执行一次")
    public Result run(@RequestBody BatchJob batchJob) {
        Result result = ResultTool.success();
        try {
            sysJobService.run(batchJob);
        } catch (SchedulerException e) {
            result = ResultTool.fail(ResultCode.BATCH_RUN_ERROR);
            return result;
        }
        return result;
    }

    /**
     * cron表达式解析
     * @param cronParserVo cron表达式
     * @return 解析结果
     */
    @PostMapping("/cronParser")
    @ApiAuth(value="batchJob.cronParser",description="cron表达式解析")
    public Result cronParser(@RequestBody CronParserVo cronParserVo) {
        Result result = ResultTool.success();
        List<String> timeList = new ArrayList<>();
        try {
            CronExpression cronExpression = new CronExpression(cronParserVo.getCron());
            int times = cronParserVo.getTimes();
            Date lastFireTime = new Date(); // 从当前时间开始
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int i = 0; i < times; i++) {
                lastFireTime = cronExpression.getNextValidTimeAfter(lastFireTime);
                timeList.add(sdf.format(lastFireTime));
            }
            result.setData(timeList);
        } catch (ParseException e) {
            result = ResultTool.fail(ResultCode.BATCH_CRON_PARSER_ERROR);
        } catch (Exception e) {
            result.setData(timeList);
        }
        return result;
    }
}
